#include "bs_struct.h"

static _list_elem_t* malloc_elem(size_t elen);

int _list_insert_head(_list_t* list, void* elem){
    int                 rv = BS_SUCCESS;
    _list_elem_t*       pe;

    assert(list!=NULL && elem!=NULL);
    pe = malloc_elem(list->elen);
    if(pe == NULL){
        return BS_NOMEM;
    }

    memcpy(pe->elem, elem, list->elen);
    pe->prev = &list->head;
    pe->next = list->head.next;
    list->head.next->prev = pe;
    list->head.next = pe;
    list->size++;

    return rv;
}

int _list_insert_rear(_list_t* list, void* elem){
    int                 rv = BS_SUCCESS;
    _list_elem_t*       pe;

    assert(list!=NULL && elem!=NULL);
    pe = malloc_elem(list->elen);
    if(pe == NULL){
        return BS_NOMEM;
    }

    memcpy(pe->elem, elem, list->elen);
    pe->prev = list->rear.prev;
    pe->next = &list->rear;
    list->rear.prev->next = pe;
    list->rear.prev = pe;
    list->size++;

    return rv;
}

int _list_insert_next(_list_t* list, void* cur, void* elem){
    int                 rv = BS_SUCCESS;
    _list_elem_t*       pe;
    _list_elem_t*       pnew;

    assert(list!=NULL && cur!=NULL && elem!=NULL);
    pe = elem_addr(cur);
    /*
    if(pe->next == NULL || pe == list->rear){
        return _list_insert_rear(list, elem);
    }
    */

    pnew = malloc_elem(list->elen);
    if(pnew == NULL){
        return BS_NOMEM;
    }
    memcpy(pnew->elem, elem, list->elen);

    pnew->next = pe->next;
    pnew->prev = pe;
    pe->next->prev = pnew;
    pe->next = pnew;
    list->size++;

    return rv;
}

int _list_insert_prev(_list_t* list, void* cur, void* elem){
    int                 rv = BS_SUCCESS;
    _list_elem_t*       pe;
    _list_elem_t*       pnew;

    assert(list!=NULL && cur!=NULL && elem!=NULL);
    /*
    if(pe->prev == NULL || pe == list->head){
        return _list_insert_head(list, elem);
    }
    */

    pe = elem_addr(cur);
    pnew = malloc_elem(list->elen);
    if(pnew == NULL){
        return BS_NOMEM;
    }
    memcpy(pnew->elem, elem, list->elen);

    pnew->prev = pe->prev;
    pnew->next = pe;
    pe->prev->next = pnew;
    pe->prev = pnew;
    list->size++;

    return rv;
}

int _list_free(_list_t* list){
    _list_elem_t*               pe;
    _list_elem_t*               next;

    for(pe=list->head.next; pe!=&list->rear; ){
        next = pe->next;
        free(pe);
        pe = next;
    }

    return BS_SUCCESS;
}

static _list_elem_t* malloc_elem(size_t elen){
    _list_elem_t*               pe;

    pe = (_list_elem_t*)malloc(sizeof(_list_elem_t)+elen);
    if(pe == NULL){
        return NULL;
    }

    pe->elem = (char*)pe + sizeof(_list_elem_t);
    return pe;
}
